home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
boot
/
netBoot.new
/
sys
/
tftp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-19
|
6KB
|
240 lines
/*
* @(#)tftp.c 1.1 86/09/27
* Copyright (c) 1986 by Sun Microsystems, Inc.
*/
/*
* Standalone network boot via TFTP
*/
#include "../dev/saio.h"
#include "../h/socket.h"
#include "../dev/if.h"
#include "../h/in.h"
#include "../dev/if_ether.h"
#include "../h/in_systm.h"
#include "../h/ip.h"
#include "../h/udp.h"
#include "../h/sainet.h"
#include "../h/sunromvec.h"
#include "../sun3/cpu.addrs.h"
#undef DEV_BSIZE
#undef MAX
#include "../h/tftp.h"
char *tftp_errs[] = {
"not defined",
"file not found",
"access violation",
"disk full or allocation exceeded",
"illegal TFTP operation",
"unknown transfer ID",
"file already exists",
"no such user"
};
#define LOADADDR 0x4000
#define millitime() (*romp->v_nmiclock)
struct tftp_pack { /* TFTP packet */
struct ether_header tf_ether; /* Ethernet header */
struct ip tf_ip; /* IP header */
struct udphdr tf_udp; /* UDP header */
struct tftphdr tf_tftp; /* TFTP header */
char tftp_data[SEGSIZE]; /* TFTP data beyond header */
};
/*
* Size of Headers in TFTP DATA packet
*/
#define TFTPHDRLEN (sizeof (struct ether_header) + sizeof (struct ip) + \
sizeof (struct udphdr) + 4)
struct tftpglob {
struct tftp_pack tf_out; /* outgoing TFTP packet */
struct sainet tf_inet; /* Internet state */
char tf_tmpbuf[1600]; /* tmp for incoming packets */
int tf_block; /* current block number */
char *tf_data; /* current load pointer */
};
#define TFTPBASE ((struct tftpglob *)0x3000)
#define REXMIT_MSEC 4000 /* 4 seconds between retransmits */
etheropen(sip)
register struct saioreq *sip;
{
register struct tftpglob *tf = TFTPBASE;
bzero((caddr_t)tf, sizeof (*tf));
inet_init(sip, &tf->tf_inet, tf->tf_tmpbuf); /* Initialize inet */
return (0);
}
etherstrategy(sip, rw)
register struct saioreq *sip;
int rw;
{
printf("tftp: random access attempted - code error.\n");
return (-1);
}
tftpload(sip)
register struct saioreq *sip;
{
register struct tftpglob *tf = TFTPBASE;
register struct tftp_pack *out = &tf->tf_out;
register struct tftp_pack *in = (struct tftp_pack *)tf->tf_tmpbuf;
register char *p, *q, *x;
register short i, len;
int autoboot = 0;
int firsttry = 0;
int feedback = 0;
int time, xcount, locked, retry;
char *ind = "-\\|/";
if (sip->si_unit == 0)
autoboot = 1; /* if unit # is 0, this is an autoboot */
top:
/*
* Initialize IP and UDP headers
*/
out->tf_ip.ip_v = IPVERSION;
out->tf_ip.ip_hl = sizeof (struct ip) / 4;
out->tf_ip.ip_ttl = MAXTTL;
out->tf_ip.ip_p = IPPROTO_UDP;
out->tf_udp.uh_sport = (millitime() & 1023) + 1024;
out->tf_udp.uh_dport = IPPORT_TFTP;
out->tf_udp.uh_sum = 0; /* no checksum */
/*
* Set src and dst host addresses
* Dst host is argument with our net number plugged in
*/
out->tf_ip.ip_src = tf->tf_inet.sain_myaddr;
if (autoboot && firsttry == 0) {
out->tf_ip.ip_dst.s_addr = tf->tf_inet.sain_hisaddr.s_addr;
} else if (autoboot && firsttry > 0) {
out->tf_ip.ip_dst.s_addr = -1;
} else {
out->tf_ip.ip_dst.s_addr = out->tf_ip.ip_src.s_addr +
sip->si_unit - in_lnaof(out->tf_ip.ip_src);
}
++firsttry;
locked = 0;
retry = 0;
tf->tf_block = 1;
tf->tf_data = (char *)LOADADDR;
/*
* Create the TFTP Read Request packet
*/
out->tf_tftp.th_opcode = RRQ;
p = out->tf_tftp.th_stuff;
q = (char *)&tf->tf_inet.sain_myaddr;
x = "0123456789ABCDEF";
for (i=0; i<4; i++) {
*p++ = x[(*q >> 4) & 0xF];
*p++ = x[(*q++) & 0xF];
}
*p++ = 0;
q = "octet";
while (*p++ = *q++)
;
out->tf_udp.uh_ulen = sizeof (struct udphdr) + 2 +
(p - out->tf_tftp.th_stuff);
out->tf_ip.ip_len = sizeof (struct ip) +
out->tf_udp.uh_ulen;
time = 0;
for (xcount = 0; xcount < 5;) {
if (millitime() - time >= REXMIT_MSEC) {
time = millitime();
printf("%c\b", ind[feedback++ % 4]); /* Show activity */
if (ip_output(sip, (caddr_t)out, out->tf_ip.ip_len +
sizeof (struct ether_header), &tf->tf_inet,
tf->tf_tmpbuf))
printf("X\b");
if (locked == 0 || retry > 15)
xcount++;
else
retry++;
}
len = ip_input(sip, (caddr_t)in, &tf->tf_inet);
if (len < TFTPHDRLEN)
continue;
if (in->tf_ip.ip_p != IPPROTO_UDP ||
in->tf_udp.uh_dport != out->tf_udp.uh_sport)
continue;
if (locked &&
out->tf_ip.ip_dst.s_addr != in->tf_ip.ip_src.s_addr) continue;
if (in->tf_tftp.th_opcode == ERROR) {
if (autoboot && tf->tf_block == 1)
continue;
if (in->tf_tftp.th_code < 0 ||
in->tf_tftp.th_code > sizeof(tftp_errs)/sizeof(char *)){
printf("tftp: Unknown error 0x%x\n",
in->tf_tftp.th_code);
} else {
printf("tftp: %s @ block %d\n",
tftp_errs[in->tf_tftp.th_code], tf->tf_block);
}
if (autoboot)
goto top;
return (-1);
}
if (in->tf_tftp.th_opcode != DATA ||
in->tf_tftp.th_block != tf->tf_block)
continue;
/*
* Here if we have an in sequence DATA packet
*/
if (tf->tf_block == 1) { /* lock on to server and port */
out->tf_udp.uh_dport = in->tf_udp.uh_sport;
if (autoboot)
out->tf_ip.ip_dst = in->tf_ip.ip_src;
printf("Booting from tftp server at ");
inet_print(out->tf_ip.ip_dst);
locked = 1;
}
/*
* Swallow data
*/
len = in->tf_udp.uh_ulen - (sizeof(struct udphdr) + 4);
if (len) {
bcopy(in->tf_tftp.th_data, tf->tf_data, len);
tf->tf_data += len;
}
/*
* Send ACK
*/
xcount = 0;
retry = 0;
out->tf_tftp.th_opcode = ACK;
out->tf_tftp.th_block = tf->tf_block++;
out->tf_udp.uh_ulen = sizeof (struct udphdr) + 4;
out->tf_ip.ip_len = sizeof (struct ip) + out->tf_udp.uh_ulen;
time = millitime();
printf("%c\b", ind[feedback++ % 4]); /* Show activity */
if (ip_output(sip, (caddr_t)out, out->tf_ip.ip_len +
sizeof (struct ether_header), &tf->tf_inet,
tf->tf_tmpbuf))
printf("X\b");
if (len < SEGSIZE) { /* end of file */
printf("Downloaded %d bytes from tftp server.\n\n",
tf->tf_data - LOADADDR);
return (LOADADDR);
}
}
printf("tftp: time-out.\n");
if (autoboot)
goto top;
return (-1);
}